package com.vision.sales.sv.report;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRPdfExporter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author Mark
 *
 */
public class ReportWriter {
	
	private static final Logger log = LoggerFactory.getLogger(ReportWriter.class);
	
	/**
	 * Writes the <tt>report</tt> into the <tt>resp</tt>.
	 * 
	 * @param report
	 * @param resp
	 * @param size
	 * @param orientation
	 * @throws JRException
	 * @throws IOException
	 */
	public static void write(Report report, HttpServletResponse resp) throws JRException, IOException {
		JasperPrint print = report.asJasperPrint();
		write(print, report.getFilename(), resp);
	}

	/**
	 * 
	 * @param print
	 * @param filename
	 * @param resp
	 * @throws JRException
	 * @throws IOException
	 */
	public static void write(JasperPrint print, String filename, HttpServletResponse resp) throws JRException, IOException {
		log.debug("Exporting JasperPrint to stream...");
		JRAbstractExporter exporter = new JRPdfExporter();
		exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
		exporter.exportReport();
		
		byte[] reportAsBytes = baos.toByteArray();
		log.info("Writing to output stream... Lenght: {}", reportAsBytes.length);

		// Set the content-length
		resp.setContentLength(reportAsBytes.length);
		
		// TODO Later provide support for other file types
		resp.setContentType("application/pdf");
		resp.setHeader("Content-Disposition", "inline; filename=" + sanitizeFilename(filename) + ".pdf");

		// Write to the response's output stream
		log.info("Writing report to servlet output stream...");
		ServletOutputStream os = resp.getOutputStream();
		os.write(reportAsBytes, 0, reportAsBytes.length);
		os.flush();
		os.close();
	}

	/**
	 * Removes characters that can be used to potentially exploit HTTP headers vulnerability.
	 * For this purpose, only alphanumeric characters and underscore are retained. Whitespaces
	 * in the filename are replaced with underscores.
	 * 
	 * @param filename
	 * @return
	 */
	public static String sanitizeFilename(String filename) {
		StringBuilder sb = new StringBuilder(filename.length());
		for (int i = 0; i < filename.length(); i++) {
			char c = filename.charAt(i);
			if (Character.isLetterOrDigit(c) || c == '_')
				sb.append(c);
			else if (Character.isWhitespace(c))
				sb.append('_');
		}
		return sb.toString();
	}

}
